package com.group.elmboot.service.impl;


import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.group.elmboot.bo.CreditTransactionBO;
import com.group.elmboot.mapper.CreditMapper;
import com.group.elmboot.mapper.OrdersMapper;
import com.group.elmboot.mapper.RedPacketMapper;
import com.group.elmboot.mapper.TransitionMapper;
import com.group.elmboot.po.CreditTransaction;
import com.group.elmboot.po.RedPacket;
import com.group.elmboot.util.CreditUtil;
import com.group.elmboot.vo.CreditTransactionVO;
import com.group.elmboot.service.CreditService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;

@Service
public class CreditServiceImpl implements CreditService {

    @Autowired
    CreditMapper creditMapper;
    @Autowired
    OrdersMapper ordersMapper;
    @Autowired
    TransitionMapper transitionMapper;
    @Autowired
    RedPacketMapper redPacketMapper;
    @Value("${myapp.globalVar.creditValidMonths}")
    int[] creditValidMonths;
    @Value("${myapp.globalVar.creditEarnRate}")
    String[] creditEarnRate;//每消费1元获得1积分，rate乘价格为赚取积分
    @Value("${myapp.globalVar.creditConsumeRate}")
    String[] creditConsumeRate;//每100积分可抵消1元，rate乘价格为消耗积分

    @Override
    public int earnCredit(CreditTransactionVO creditTransactionVO) throws Exception {
        CreditTransactionBO creditTransactionBO = new CreditTransactionBO(creditTransactionVO);
        System.out.println(creditEarnRate[0]);
        int credit= CreditUtil.getCreditByChannelIdByEventId(true,creditTransactionBO.getChannelId(),creditTransactionBO.getEventId(),ordersMapper,transitionMapper,creditEarnRate,creditConsumeRate);
        creditTransactionBO.setCredit(credit);
        creditTransactionBO.setExpiredTime(LocalDateTime.now().plusMonths(creditValidMonths[creditTransactionBO.getChannelId()]));
        return creditMapper.insert(new CreditTransaction(creditTransactionBO));
    }

    @Override
    @Transactional
    public int consumeCredit(CreditTransactionVO creditTransactionVO) throws Exception {
        CreditTransactionBO creditTransactionBO = new CreditTransactionBO(creditTransactionVO);
        int credit= CreditUtil.getCreditByChannelIdByEventId(false,creditTransactionBO.getChannelId(),creditTransactionBO.getEventId(),ordersMapper,transitionMapper,creditEarnRate,creditConsumeRate);
        creditTransactionBO.setCredit(credit*-1);
        RedPacket redPacket =new RedPacket(creditTransactionBO.getUserId(),creditTransactionBO.getEventId(),LocalDateTime.now());
        if(getCreditById(creditTransactionBO.getUserId())+creditTransactionBO.getCredit()<0){
            return -1;//Insufficient Credit
        }
        redPacketMapper.insert(redPacket);
        return creditMapper.insert(new CreditTransaction(creditTransactionBO));
    }

    @Override
    public int getCreditById(String userId) {
        List<CreditTransaction> pos=creditMapper.selectList(new EntityWrapper<CreditTransaction>().eq("user_id",userId).gt("credit",0).orderBy("expired_time"));
        List<CreditTransaction> neg=creditMapper.selectList(new EntityWrapper<CreditTransaction>().eq("user_id",userId).lt("credit",0).orderBy("create_time"));
        int ptr=0,credit=0;
        for (CreditTransaction negTransaction : neg) {
            LocalDateTime createTime = negTransaction.getCreateTime();
            int negCredit = negTransaction.getCredit() * -1;
            negTransaction.setCredit(0);
            while (negCredit > 0) {
                CreditTransaction posTransaction = pos.get(ptr);
                int posCredit = posTransaction.getCredit();
                LocalDateTime expiredTime = posTransaction.getExpiredTime();
                if (expiredTime.isAfter(createTime)) {
                    if (negCredit >posCredit) {
                        posTransaction.setCredit(0);
                        ptr++;
                    } else {
                        posTransaction.setCredit(posCredit - negCredit);
                        if (negCredit == posCredit)
                            ptr++;
                    }
                    negCredit -= posCredit;
                }
                else
                    ptr++;
            }
        }
        for (int i = ptr; i < pos.size(); i++) {
            CreditTransaction posTransaction=pos.get(i);
            if (posTransaction.getExpiredTime().isBefore(LocalDateTime.now()))
                i++;
            else
                credit+= posTransaction.getCredit();
        }

        return credit;
    }

    @Override
    public List<CreditTransaction> listCreditTransactionByPage(String userId, int current,int size) {
        Page<CreditTransaction> page=new Page<>(current,size);
        return creditMapper.selectPage(page,new EntityWrapper<CreditTransaction>().eq("user_id",userId).orderBy("create_time"));
    }

    @Override
    public List<CreditTransaction> listCreditEarnTransactionByPage(String userId, int current,int size) {
        Page<CreditTransaction> page=new Page<>(current,size);
        return creditMapper.selectPage(page,new EntityWrapper<CreditTransaction>().eq("user_id",userId).gt("credit",0).orderBy("create_time"));
    }

    @Override
    public List<CreditTransaction> listCreditConsumeTransactionByPage(String userId, int current,int size) {
        Page<CreditTransaction> page=new Page<>(current,size);
        return creditMapper.selectPage(page,new EntityWrapper<CreditTransaction>().eq("user_id",userId).lt("credit",0).orderBy("create_time"));
    }

    @Override
    public List<RedPacket> listAvailableRedPackets(String userId, int current, int size) {
        Page<RedPacket> page=new Page<>(current,size);
        return redPacketMapper.selectPage(page,new EntityWrapper<RedPacket>().eq("user_id",userId).eq("used",0));
    }

    @Override
    public List<RedPacket> listAllRedPackets(String userId, int current, int size) {
        Page<RedPacket> page=new Page<>(current,size);
        return redPacketMapper.selectPage(page,new EntityWrapper<RedPacket>().eq("user_id",userId));
    }

    @Override
    public List<RedPacket> listUsedRedPackets(String userId, int current, int size) {
        Page<RedPacket> page=new Page<>(current,size);
        return redPacketMapper.selectPage(page,new EntityWrapper<RedPacket>().eq("user_id",userId).eq("used",1));
    }

    @Override
    public List<RedPacket> listAllUsedRedPackets(String userId) {
        return redPacketMapper.selectList(new EntityWrapper<RedPacket>().eq("user_id",userId).eq("used",1));
    }

    @Override
    public int getAvailableRedPacketCategory(String userId) {
        int ret=0;
        if(redPacketMapper.selectCount(new EntityWrapper<RedPacket>().eq("user_id",userId).eq("used",0).eq("amount",3))>0)
            ret+=1;
        if(redPacketMapper.selectCount(new EntityWrapper<RedPacket>().eq("user_id",userId).eq("used",0).eq("amount",5))>0)
            ret+=2;
        if(redPacketMapper.selectCount(new EntityWrapper<RedPacket>().eq("user_id",userId).eq("used",0).eq("amount",10))>0)
            ret+=4;
        return ret;
    }

    @Override
    public int redPacketUse(String userId, int amount,int orderId) {
        Page<RedPacket> page=new Page<>(1,1);
        int id=redPacketMapper.selectPage(page,new EntityWrapper<RedPacket>().eq("user_id",userId).eq("used",0)).get(0).getId();
        RedPacket redPacket=new RedPacket(id,userId,amount,orderId);
        return redPacketMapper.updateById(redPacket);
    }
}
